Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / tests / backend / test_performance_hotpaths.py

Displaying Raw • Download


tests/backend/test_performance_hotpaths.py b1b9846ac58289ad2ac7f6564863fc97dd720128 (b1b9846a) Text, 30.60 KB

T8b949e"""Performance regression tests for the critical hot paths.

Excluded from default `task test:be` / CI; run locally with `task test:be:perf`
or `task test:be:full` (see Taskfile.yml).

Focus areas (user priority):
- NomadNet browser: load announces, search announces, favourites
- Messages: load conversations, search messages, load conversation messages,
upsert messages (drafts)

Metrics collected:
- ops/sec throughput
- p50 / p95 / p99 latency
- Concurrent writer contention
- LIKE-search scaling

Latency and single-thread throughput tests use fixed ceilings/floors. Message
upsert throughput uses 300 ops/s locally; under CI a lower floor applies unless
MESHCHATX_PERF_MIN_MESSAGE_UPSERT_OPS is set. Concurrent writer tests use the
same on non-CI hardware; under CI a lower throughput floor applies unless
MESHCHATX_PERF_MIN_CONCURRENT_OPS is set.
"""

Tff7b72import T7ee787os
Tff7b72import T7ee787secrets
Tff7b72import T7ee787shutil
Tff7b72import T7ee787statistics
Tff7b72import T7ee787tempfile
Tff7b72import T7ee787threading
Tff7b72import T7ee787time
Tff7b72import T7ee787unittest

Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787announce_manager Tff7b72import Te6edf3AnnounceManager
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787database Tff7b72import Te6edf3Database
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787message_handler Tff7b72import Te6edf3MessageHandler

T8b949e# ---------------------------------------------------------------------------
T8b949e# Helpers
T8b949e# ---------------------------------------------------------------------------


Tff7b72def Td2a8ff_min_message_upsert_throughput_opsTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Minimum single-thread upsert/update ops/s for regression tests.

Local runs use a strict floor (300). CI runners are often noisy; a dip
just below 300 is not a regression. Override with
MESHCHATX_PERF_MIN_MESSAGE_UPSERT_OPS.
"""
Te6edf3raw Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_PERF_MIN_MESSAGE_UPSERT_OPSTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3raw Tff7b72is Tff7b72not Tff7b72None Tff7b72and Te6edf3rawTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72!= Ta5d6ff"Ta5d6ff"Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72return Tffa657maxTb4b4b4(T79c0ff1Tb4b4b4, Tffa657intTb4b4b4(Te6edf3rawTb4b4b4, T79c0ff10Tb4b4b4)Tb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72pass
Tff7b72if Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffCITa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return T79c0ff250
Tff7b72return T79c0ff300


Tff7b72def Td2a8ff_min_concurrent_throughput_opsTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e"""Minimum aggregate ops/s for concurrent writer tests.

Local runs use a strict floor. CI runners are often CPU-starved or on slow
shared storage; wall-clock throughput there is not comparable to dev
hardware. Override with MESHCHATX_PERF_MIN_CONCURRENT_OPS.
"""
Te6edf3raw Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_PERF_MIN_CONCURRENT_OPSTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3raw Tff7b72is Tff7b72not Tff7b72None Tff7b72and Te6edf3rawTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72!= Ta5d6ff"Ta5d6ff"Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72return Tffa657maxTb4b4b4(T79c0ff1Tb4b4b4, Tffa657intTb4b4b4(Te6edf3rawTb4b4b4, T79c0ff10Tb4b4b4)Tb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72pass
Tff7b72if Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffCITa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return T79c0ff20
Tff7b72return T79c0ff100


Tff7b72def Td2a8ffpercentileTb4b4b4(Te6edf3dataTb4b4b4, Te6edf3pctTb4b4b4)Tb4b4b4:
T8b949e"""Return the pct-th percentile of sorted data."""
Tff7b72if Tff7b72not Te6edf3dataTb4b4b4:
Tff7b72return T79c0ff0
Te6edf3s Tff7b72= Tffa657sortedTb4b4b4(Te6edf3dataTb4b4b4)
Te6edf3k Tff7b72= Tb4b4b4(Tffa657lenTb4b4b4(Te6edf3sTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4) Tff7b72* Tb4b4b4(Te6edf3pct Tff7b72/ T79c0ff100Tb4b4b4)
Te6edf3f Tff7b72= Tffa657intTb4b4b4(Te6edf3kTb4b4b4)
Te6edf3c Tff7b72= Te6edf3f Tff7b72+ T79c0ff1
Tff7b72if Te6edf3c Tff7b72>Tff7b72= Tffa657lenTb4b4b4(Te6edf3sTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3sTb4b4b4[Te6edf3fTb4b4b4]
Tff7b72return Te6edf3sTb4b4b4[Te6edf3fTb4b4b4] Tff7b72+ Tb4b4b4(Te6edf3k Tff7b72- Te6edf3fTb4b4b4) Tff7b72* Tb4b4b4(Te6edf3sTb4b4b4[Te6edf3cTb4b4b4] Tff7b72- Te6edf3sTb4b4b4[Te6edf3fTb4b4b4]Tb4b4b4)


Tff7b72def Td2a8fftimed_callTb4b4b4(Te6edf3fnTb4b4b4, Tff7b72*Te6edf3argsTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)Tb4b4b4:
T8b949e"""Call fn and return (result, duration_ms)."""
Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Te6edf3result Tff7b72= Te6edf3fnTb4b4b4(Tff7b72*Te6edf3argsTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)
Tff7b72return Te6edf3resultTb4b4b4, Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000


Tff7b72def Td2a8fflatency_reportTb4b4b4(Te6edf3nameTb4b4b4, Te6edf3durations_msTb4b4b4)Tb4b4b4:
T8b949e"""Print and return latency stats."""
Te6edf3p50 Tff7b72= Te6edf3percentileTb4b4b4(Te6edf3durations_msTb4b4b4, T79c0ff50Tb4b4b4)
Te6edf3p95 Tff7b72= Te6edf3percentileTb4b4b4(Te6edf3durations_msTb4b4b4, T79c0ff95Tb4b4b4)
Te6edf3p99 Tff7b72= Te6edf3percentileTb4b4b4(Te6edf3durations_msTb4b4b4, T79c0ff99Tb4b4b4)
Te6edf3avg Tff7b72= Te6edf3statisticsTff7b72.Td2a8ffmeanTb4b4b4(Te6edf3durations_msTb4b4b4)
Te6edf3ops Tff7b72= T79c0ff1000 Tff7b72/ Te6edf3avg Tff7b72if Te6edf3avg Tff7b72> T79c0ff0 Tff7b72else Tffa657floatTb4b4b4(Ta5d6ff"Ta5d6ffinfTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3nameTffd700}Ta5d6ff: avg=Tffd700{Te6edf3avgTffd700:Ta5d6ff.2fTffd700}Ta5d6ffms p50=Tffd700{Te6edf3p50Tffd700:Ta5d6ff.2fTffd700}Ta5d6ffms p95=Tffd700{Te6edf3p95Tffd700:Ta5d6ff.2fTffd700}Ta5d6ffms Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffp99=Tffd700{Te6edf3p99Tffd700:Ta5d6ff.2fTffd700}Ta5d6ffms ops/s=Tffd700{Te6edf3opsTffd700:Ta5d6ff.0fTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Tb4b4b4{Ta5d6ff"Ta5d6ffavgTa5d6ff"Tb4b4b4: Te6edf3avgTb4b4b4, Ta5d6ff"Ta5d6ffp50Ta5d6ff"Tb4b4b4: Te6edf3p50Tb4b4b4, Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4: Te6edf3p95Tb4b4b4, Ta5d6ff"Ta5d6ffp99Ta5d6ff"Tb4b4b4: Te6edf3p99Tb4b4b4, Ta5d6ff"Ta5d6ffopsTa5d6ff"Tb4b4b4: Te6edf3opsTb4b4b4}


Tff7b72def Td2a8ffmake_messageTb4b4b4(Te6edf3peer_hashTb4b4b4, Te6edf3iTb4b4b4, Te6edf3content_sizeTff7b72=T79c0ff100Tb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4: Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffsource_hashTa5d6ff"Tb4b4b4: Te6edf3peer_hashTb4b4b4,
Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fflocal_hash_0Ta5d6ff" Tff7b72* T79c0ff2Tb4b4b4,
Ta5d6ff"Ta5d6ffpeer_hashTa5d6ff"Tb4b4b4: Te6edf3peer_hashTb4b4b4,
Ta5d6ff"Ta5d6ffstateTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffdeliveredTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffprogressTa5d6ff"Tb4b4b4: T79c0ff1.0Tb4b4b4,
Ta5d6ff"Ta5d6ffis_incomingTa5d6ff"Tb4b4b4: Te6edf3i Tff7b72% T79c0ff2Tb4b4b4,
Ta5d6ff"Ta5d6ffmethodTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffdirectTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdelivery_attemptsTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffnext_delivery_attempt_atTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffMessage title Tffd700{Te6edf3iTffd700}Ta5d6ff Ta5d6ff" Tff7b72+ Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff8Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffContent body Tffd700{Te6edf3iTffd700}Ta5d6ff Ta5d6ff" Tff7b72+ Ta5d6ff"Ta5d6ffxTa5d6ff" Tff7b72* Te6edf3content_sizeTb4b4b4,
Ta5d6ff"Ta5d6fffieldsTa5d6ff"Tb4b4b4: Ta5d6ff"Tffd700{}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fftimestampTa5d6ff"Tb4b4b4: Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3iTb4b4b4,
Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4: Tff7b72-T79c0ff50Tb4b4b4,
Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4: T79c0ff5.0Tb4b4b4,
Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4: T79c0ff3Tb4b4b4,
Ta5d6ff"Ta5d6ffis_spamTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffreply_to_hashTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Tb4b4b4}


Tff7b72def Td2a8ffmake_announceTb4b4b4(Te6edf3iTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4: Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffaspectTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff" Tff7b72if Te6edf3i Tff7b72% T79c0ff3 Tff7b72!= T79c0ff0 Tff7b72else Ta5d6ff"Ta5d6fflxst.telephonyTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidentity_hashTa5d6ff"Tb4b4b4: Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffidentity_public_keyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffpubkey_Ta5d6ff" Tff7b72+ Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff8Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffapp_dataTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffappdata_Ta5d6ff" Tff7b72+ Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4: Tff7b72-T79c0ff50 Tff7b72+ Tb4b4b4(Te6edf3i Tff7b72% T79c0ff30Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4: T79c0ff5.0Tb4b4b4,
Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4: Te6edf3i Tff7b72% T79c0ff10Tb4b4b4,
Tb4b4b4}


T8b949e# ---------------------------------------------------------------------------
T8b949e# Test class
T8b949e# ---------------------------------------------------------------------------


Tff7b72class T56d364TestPerformanceHotPathsTb4b4b4(Te6edf3unittestTff7b72.Td2a8ffTestCaseTb4b4b4)Tb4b4b4:
Te6edf3NUM_MESSAGES Tff7b72= T79c0ff10_000
Te6edf3NUM_PEERS Tff7b72= T79c0ff200
Te6edf3NUM_ANNOUNCES Tff7b72= T79c0ff5_000
Te6edf3NUM_FAVOURITES Tff7b72= T79c0ff100
Te6edf3NUM_CONTACTS Tff7b72= T79c0ff50

Tf0883e@classmethod
Tff7b72def Td2a8ffsetUpClassTb4b4b4(Tff7b72clsTb4b4b4)Tb4b4b4:
Tff7b72clsTff7b72.Td2a8fftest_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ffdb_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72clsTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffperf_hotpaths.dbTa5d6ff"Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ffdb Tff7b72= Te6edf3DatabaseTb4b4b4(Tff7b72clsTff7b72.Td2a8ffdb_pathTb4b4b4)
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffinitializeTb4b4b4(Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ffhandler Tff7b72= Te6edf3MessageHandlerTb4b4b4(Tff7b72clsTff7b72.Td2a8ffdbTb4b4b4)
Tff7b72clsTff7b72.Td2a8ffannounce_mgr Tff7b72= Te6edf3AnnounceManagerTb4b4b4(Tff7b72clsTff7b72.Td2a8ffdbTb4b4b4)

Tff7b72clsTff7b72.Td2a8ff_seed_dataTb4b4b4(Tb4b4b4)

Tf0883e@classmethod
Tff7b72def Td2a8fftearDownClassTb4b4b4(Tff7b72clsTb4b4b4)Tb4b4b4:
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Tff7b72clsTff7b72.Td2a8fftest_dirTb4b4b4, Te6edf3ignore_errorsTff7b72=Tff7b72TrueTb4b4b4)

Tf0883e@classmethod
Tff7b72def Td2a8ff_seed_dataTb4b4b4(Tff7b72clsTb4b4b4)Tb4b4b4:
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff--- Seeding test data ---Ta5d6ff"Tb4b4b4)

T8b949e# Peers
Tff7b72clsTff7b72.Td2a8ffpeer_hashes Tff7b72= Tb4b4b4[Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(Tff7b72clsTff7b72.Td2a8ffNUM_PEERSTb4b4b4)Tb4b4b4]
Tff7b72clsTff7b72.Td2a8ffheavy_peer Tff7b72= Tff7b72clsTff7b72.Td2a8ffpeer_hashesTb4b4b4[T79c0ff0Tb4b4b4]

T8b949e# Messages: distribute across peers, heavy_peer gets 2000
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Seeding Tffd700{Tff7b72clsTff7b72.Td2a8ffNUM_MESSAGESTffd700}Ta5d6ff messages across Tffd700{Tff7b72clsTff7b72.Td2a8ffNUM_PEERSTffd700}Ta5d6ff peers...Ta5d6ff"Tb4b4b4)
Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Tff7b72with Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Tff7b72clsTff7b72.Td2a8ffNUM_MESSAGESTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3i Tff7b72< T79c0ff2000Tb4b4b4:
Te6edf3peer Tff7b72= Tff7b72clsTff7b72.Td2a8ffheavy_peer
Tff7b72elseTb4b4b4:
Te6edf3peer Tff7b72= Tff7b72clsTff7b72.Td2a8ffpeer_hashesTb4b4b4[Te6edf3i Tff7b72% Tff7b72clsTff7b72.Td2a8ffNUM_PEERSTb4b4b4]
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4(Te6edf3make_messageTb4b4b4(Te6edf3peerTb4b4b4, Te6edf3iTb4b4b4)Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Done in Tffd700{Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000Tffd700:Ta5d6ff.0fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)

T8b949e# Announces
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Seeding Tffd700{Tff7b72clsTff7b72.Td2a8ffNUM_ANNOUNCESTffd700}Ta5d6ff announces...Ta5d6ff"Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ffannounce_hashes Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Tff7b72with Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Tff7b72clsTff7b72.Td2a8ffNUM_ANNOUNCESTb4b4b4)Tb4b4b4:
Te6edf3data Tff7b72= Te6edf3make_announceTb4b4b4(Te6edf3iTb4b4b4)
Tff7b72clsTff7b72.Td2a8ffannounce_hashesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3dataTb4b4b4[Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4]Tb4b4b4)
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffupsert_announceTb4b4b4(Te6edf3dataTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Done in Tffd700{Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000Tffd700:Ta5d6ff.0fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)

T8b949e# Favourites
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Seeding Tffd700{Tff7b72clsTff7b72.Td2a8ffNUM_FAVOURITESTffd700}Ta5d6ff favourites...Ta5d6ff"Tb4b4b4)
Tff7b72with Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Tff7b72clsTff7b72.Td2a8ffNUM_FAVOURITESTb4b4b4)Tb4b4b4:
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffupsert_favouriteTb4b4b4(
Tff7b72clsTff7b72.Td2a8ffannounce_hashesTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffFav Node Tffd700{Te6edf3iTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e# Contacts (for JOIN benchmarks)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Seeding Tffd700{Tff7b72clsTff7b72.Td2a8ffNUM_CONTACTSTffd700}Ta5d6ff contacts...Ta5d6ff"Tb4b4b4)
Tff7b72with Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTb4b4b4:
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Tff7b72clsTff7b72.Td2a8ffNUM_CONTACTSTb4b4b4)Tb4b4b4:
Tff7b72clsTff7b72.Td2a8ffdbTff7b72.Td2a8ffcontactsTff7b72.Td2a8ffadd_contactTb4b4b4(
Te6edf3nameTff7b72=Ta5d6fffTa5d6ff"Ta5d6ffContact Tffd700{Te6edf3iTffd700}Ta5d6ff"Tb4b4b4,
Te6edf3remote_identity_hashTff7b72=Tff7b72clsTff7b72.Td2a8ffpeer_hashesTb4b4b4[Te6edf3i Tff7b72% Tff7b72clsTff7b72.Td2a8ffNUM_PEERSTb4b4b4]Tb4b4b4,
Te6edf3lxmf_addressTff7b72=Tff7b72clsTff7b72.Td2a8ffpeer_hashesTb4b4b4[Tb4b4b4(Te6edf3i Tff7b72+ T79c0ff1Tb4b4b4) Tff7b72% Tff7b72clsTff7b72.Td2a8ffNUM_PEERSTb4b4b4]Tb4b4b4,
Tb4b4b4)

Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ff--- Seeding complete ---Tffea00\nTa5d6ff"Tb4b4b4)

T8b949e# ===================================================================
T8b949e# ANNOUNCES — load, search, count
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_announce_load_filtered_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Load announces filtered by aspect with pagination — the NomadNet browser default view."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Announce] Filtered load (aspect + pagination):Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3offsets Tff7b72= Tb4b4b4[T79c0ff0Tb4b4b4, T79c0ff100Tb4b4b4, T79c0ff500Tb4b4b4, T79c0ff1000Tb4b4b4, T79c0ff2000Tb4b4b4]
Tff7b72for Te6edf3offset Tff7b72in Te6edf3offsetsTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffannounce_mgrTff7b72.Td2a8ffget_filtered_announcesTb4b4b4,
Te6edf3aspectTff7b72=Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6fffiltered_loadTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp99Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff100Tb4b4b4, Ta5d6ff"Ta5d6ffAnnounce filtered load p99 > 100msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_announce_search_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Search announces by destination/identity hash substring."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Announce] LIKE search:Ta5d6ff"Tb4b4b4)
Te6edf3search_terms Tff7b72= Tb4b4b4[
Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffabcTa5d6ff"Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffannounce_hashesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Tb4b4b4:T79c0ff8Tb4b4b4]Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffannounce_hashesTb4b4b4[T79c0ff2500Tb4b4b4]Tb4b4b4[Tb4b4b4:T79c0ff10Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6ffnonexistent_term_xyzTa5d6ff"Tb4b4b4,
Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3term Tff7b72in Te6edf3search_termsTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffannounce_mgrTff7b72.Td2a8ffget_filtered_announcesTb4b4b4,
Te6edf3aspectTff7b72=Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Te6edf3queryTff7b72=Te6edf3termTb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Te6edf3offsetTff7b72=T79c0ff0Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffsearchTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff150Tb4b4b4, Ta5d6ff"Ta5d6ffAnnounce search p95 > 150msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_announce_search_with_blockedTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Search with a block-list — simulates real NomadNet browser filtering."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Announce] Search with blocked list:Ta5d6ff"Tb4b4b4)
Te6edf3blocked Tff7b72= Tb4b4b4[Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff50Tb4b4b4)Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff20Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffannounce_mgrTff7b72.Td2a8ffget_filtered_announcesTb4b4b4,
Te6edf3aspectTff7b72=Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Te6edf3queryTff7b72=Ta5d6ff"Ta5d6ffabcTa5d6ff"Tb4b4b4,
Te6edf3blocked_identity_hashesTff7b72=Te6edf3blockedTb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Te6edf3offsetTff7b72=T79c0ff0Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffsearch+blockedTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff200Tb4b4b4, Ta5d6ff"Ta5d6ffAnnounce search+blocked p95 > 200msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_announce_count_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Count announces (used for pagination total)."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Announce] Count:Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff30Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffannounce_mgrTff7b72.Td2a8ffget_filtered_announces_countTb4b4b4,
Te6edf3aspectTff7b72=Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffcountTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff100Tb4b4b4, Ta5d6ff"Ta5d6ffAnnounce count p95 > 100msTa5d6ff"Tb4b4b4)

T8b949e# ===================================================================
T8b949e# FAVOURITES
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_favourites_load_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Load all favourites — typically displayed in sidebar."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Favourites] Load all:Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff50Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffget_favouritesTb4b4b4, Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffload_favsTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff20Tb4b4b4, Ta5d6ff"Ta5d6ffFavourites load p95 > 20msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_favourite_upsert_throughputTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Measure upsert throughput for favourites."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Favourites] Upsert throughput:Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4:
Te6edf3dest Tff7b72= Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffupsert_favouriteTb4b4b4,
Te6edf3destTb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffBench Fav Tffd700{Te6edf3iTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffupsert_favTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffopsTa5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff500Tb4b4b4, Ta5d6ff"Ta5d6ffFavourite upsert < 500 ops/sTa5d6ff"Tb4b4b4)

T8b949e# ===================================================================
T8b949e# CONVERSATIONS — load, search
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_conversations_load_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Load conversation list — the main messages sidebar query."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Conversations] Load list (with JOINs):Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff20Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffget_conversationsTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Te6edf3offsetTff7b72=T79c0ff0Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffload_conversationsTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff200Tb4b4b4, Ta5d6ff"Ta5d6ffConversation list p95 > 200msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_conversations_search_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Search conversations — LIKE across titles, content, peer hashes."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Conversations] Search:Ta5d6ff"Tb4b4b4)
Te6edf3terms Tff7b72= Tb4b4b4[
Ta5d6ff"Ta5d6ffMessage title 5Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContent bodyTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffabcTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffzzz_nopeTa5d6ff"Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffheavy_peerTb4b4b4[Tb4b4b4:T79c0ff8Tb4b4b4]Tb4b4b4,
Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3term Tff7b72in Te6edf3termsTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffget_conversationsTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Te6edf3searchTff7b72=Te6edf3termTb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffsearch_conversationsTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff500Tb4b4b4, Ta5d6ff"Ta5d6ffConversation search p95 > 500msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_conversations_load_paginatedTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Paginate through conversation list at various offsets."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Conversations] Paginated load:Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3offset Tff7b72in Tb4b4b4[T79c0ff0Tb4b4b4, T79c0ff20Tb4b4b4, T79c0ff50Tb4b4b4, T79c0ff100Tb4b4b4, T79c0ff150Tb4b4b4]Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffget_conversationsTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Te6edf3limitTff7b72=T79c0ff20Tb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffpaginated_conversationsTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff300Tb4b4b4, Ta5d6ff"Ta5d6ffPaginated conversations p95 > 300msTa5d6ff"Tb4b4b4)

T8b949e# ===================================================================
T8b949e# MESSAGES — load, search, upsert (drafts)
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_message_load_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Load messages for a single conversation (heavy peer with 2000 msgs)."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Messages] Load conversation messages:Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3offsets Tff7b72= Tb4b4b4[T79c0ff0Tb4b4b4, T79c0ff100Tb4b4b4, T79c0ff500Tb4b4b4, T79c0ff1000Tb4b4b4, T79c0ff1900Tb4b4b4]
Tff7b72for Te6edf3offset Tff7b72in Te6edf3offsetsTb4b4b4:
Te6edf3resultTb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffget_conversation_messagesTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffheavy_peerTb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Te6edf3offsetTff7b72=Te6edf3offsetTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tffa657lenTb4b4b4(Te6edf3resultTb4b4b4)Tb4b4b4, T79c0ff50Tb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffload_messagesTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp99Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff50Tb4b4b4, Ta5d6ff"Ta5d6ffMessage load p99 > 50msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_message_search_latencyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Search messages across all conversations — the global search."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Messages] Global search:Ta5d6ff"Tb4b4b4)
Te6edf3terms Tff7b72= Tb4b4b4[
Ta5d6ff"Ta5d6ffMessage title 100Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContent body 5000Ta5d6ff"Tb4b4b4,
Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffnonexistent_xyz_123Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3term Tff7b72in Te6edf3termsTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffsearch_messagesTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Te6edf3termTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffsearch_messagesTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff300Tb4b4b4, Ta5d6ff"Ta5d6ffMessage search p95 > 300msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_message_upsert_throughputTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Measure message upsert throughput — simulates saving drafts rapidly."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Messages] Upsert throughput (draft saves):Ta5d6ff"Tb4b4b4)
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3peer Tff7b72= Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4:
Te6edf3msg Tff7b72= Te6edf3make_messageTb4b4b4(Te6edf3peerTb4b4b4, Te6edf3i Tff7b72+ T79c0ff100000Tb4b4b4)
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4, Te6edf3msgTb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffupsert_messageTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Te6edf3min_ops Tff7b72= Te6edf3_min_message_upsert_throughput_opsTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(
Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffopsTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3min_opsTb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffMessage upsert < Tffd700{Te6edf3min_opsTffd700}Ta5d6ff ops/sTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff10Tb4b4b4, Ta5d6ff"Ta5d6ffMessage upsert p95 > 10msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_message_upsert_update_throughputTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Measure message UPDATE throughput — re-saving existing messages (state changes)."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Messages] Update existing messages:Ta5d6ff"Tb4b4b4)
Te6edf3peer Tff7b72= Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Te6edf3msgs Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff100Tb4b4b4)Tb4b4b4:
Te6edf3msg Tff7b72= Te6edf3make_messageTb4b4b4(Te6edf3peerTb4b4b4, Te6edf3i Tff7b72+ T79c0ff200000Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4(Te6edf3msgTb4b4b4)
Te6edf3msgsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msgTb4b4b4)

Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3msg Tff7b72in Te6edf3msgsTb4b4b4:
Te6edf3msgTb4b4b4[Ta5d6ff"Ta5d6ffstateTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6fffailedTa5d6ff"
Te6edf3msgTb4b4b4[Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ffUpdated content Ta5d6ff" Tff7b72+ Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4, Te6edf3msgTb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffupdate_messageTa5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Te6edf3min_ops Tff7b72= Te6edf3_min_message_upsert_throughput_opsTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(
Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffopsTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3min_opsTb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffMessage update < Tffd700{Te6edf3min_opsTffd700}Ta5d6ff ops/sTa5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e# ===================================================================
T8b949e# CONCURRENT WRITERS — contention stress
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_concurrent_message_writersTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Multiple threads inserting messages simultaneously."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Concurrency] Message writers:Ta5d6ff"Tb4b4b4)
Te6edf3num_threads Tff7b72= T79c0ff8
Te6edf3msgs_per_thread Tff7b72= T79c0ff100
Te6edf3errors Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3all_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffwriterTb4b4b4(Te6edf3thread_idTb4b4b4)Tb4b4b4:
Te6edf3thread_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3peer Tff7b72= Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Te6edf3msgs_per_threadTb4b4b4)Tb4b4b4:
Te6edf3msg Tff7b72= Te6edf3make_messageTb4b4b4(Te6edf3peerTb4b4b4, Te6edf3thread_id Tff7b72* T79c0ff10000 Tff7b72+ Te6edf3iTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4, Te6edf3msgTb4b4b4)
Te6edf3thread_durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3errorsTff7b72.Td2a8ffappendTb4b4b4(Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3lockTb4b4b4:
Te6edf3all_durationsTff7b72.Td2a8ffextendTb4b4b4(Te6edf3thread_durationsTb4b4b4)

Te6edf3threads Tff7b72= Tb4b4b4[
Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3writerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3tTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3t Tff7b72in Tffa657rangeTb4b4b4(Te6edf3num_threadsTb4b4b4)
Tb4b4b4]
Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3tTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3tTff7b72.Td2a8ffjoinTb4b4b4(Tb4b4b4)
Te6edf3wall_ms Tff7b72= Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000

Te6edf3total_ops Tff7b72= Te6edf3num_threads Tff7b72* Te6edf3msgs_per_thread
Te6edf3throughput Tff7b72= Te6edf3total_ops Tff7b72/ Tb4b4b4(Te6edf3wall_ms Tff7b72/ T79c0ff1000Tb4b4b4)
Tffa657printTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff Wall time: Tffd700{Te6edf3wall_msTffd700:Ta5d6ff.0fTffd700}Ta5d6ffms for Tffd700{Te6edf3total_opsTffd700}Ta5d6ff inserts (Tffd700{Te6edf3throughputTffd700:Ta5d6ff.0fTffd700}Ta5d6ff ops/s)Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffconcurrent_writeTa5d6ff"Tb4b4b4, Te6edf3all_durationsTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tffa657lenTb4b4b4(Te6edf3errorsTb4b4b4)Tb4b4b4, T79c0ff0Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffWriter errors: Tffd700{Te6edf3errorsTb4b4b4[Tb4b4b4:T79c0ff5Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Te6edf3floor Tff7b72= Te6edf3_min_concurrent_throughput_opsTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(
Te6edf3throughputTb4b4b4,
Te6edf3floorTb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffConcurrent write throughput < Tffd700{Te6edf3floorTffd700}Ta5d6ff ops/sTa5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftest_concurrent_announce_writersTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Multiple threads upserting announces simultaneously."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Concurrency] Announce writers:Ta5d6ff"Tb4b4b4)
Te6edf3num_threads Tff7b72= T79c0ff6
Te6edf3announces_per_thread Tff7b72= T79c0ff100
Te6edf3errors Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3all_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffwriterTb4b4b4(Te6edf3thread_idTb4b4b4)Tb4b4b4:
Te6edf3thread_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Te6edf3announces_per_threadTb4b4b4)Tb4b4b4:
Te6edf3data Tff7b72= Te6edf3make_announceTb4b4b4(Te6edf3thread_id Tff7b72* T79c0ff10000 Tff7b72+ Te6edf3iTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffupsert_announceTb4b4b4, Te6edf3dataTb4b4b4)
Te6edf3thread_durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3errorsTff7b72.Td2a8ffappendTb4b4b4(Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3lockTb4b4b4:
Te6edf3all_durationsTff7b72.Td2a8ffextendTb4b4b4(Te6edf3thread_durationsTb4b4b4)

Te6edf3threads Tff7b72= Tb4b4b4[
Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3writerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3tTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3t Tff7b72in Tffa657rangeTb4b4b4(Te6edf3num_threadsTb4b4b4)
Tb4b4b4]
Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3tTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3threadsTb4b4b4:
Te6edf3tTff7b72.Td2a8ffjoinTb4b4b4(Tb4b4b4)
Te6edf3wall_ms Tff7b72= Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000

Te6edf3total_ops Tff7b72= Te6edf3num_threads Tff7b72* Te6edf3announces_per_thread
Te6edf3throughput Tff7b72= Te6edf3total_ops Tff7b72/ Tb4b4b4(Te6edf3wall_ms Tff7b72/ T79c0ff1000Tb4b4b4)
Tffa657printTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff Wall time: Tffd700{Te6edf3wall_msTffd700:Ta5d6ff.0fTffd700}Ta5d6ffms for Tffd700{Te6edf3total_opsTffd700}Ta5d6ff upserts (Tffd700{Te6edf3throughputTffd700:Ta5d6ff.0fTffd700}Ta5d6ff ops/s)Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffconcurrent_announce_writeTa5d6ff"Tb4b4b4, Te6edf3all_durationsTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tffa657lenTb4b4b4(Te6edf3errorsTb4b4b4)Tb4b4b4, T79c0ff0Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffWriter errors: Tffd700{Te6edf3errorsTb4b4b4[Tb4b4b4:T79c0ff5Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Te6edf3floor Tff7b72= Te6edf3_min_concurrent_throughput_opsTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertGreaterTb4b4b4(
Te6edf3throughputTb4b4b4,
Te6edf3floorTb4b4b4,
Ta5d6fffTa5d6ff"Ta5d6ffConcurrent announce write < Tffd700{Te6edf3floorTffd700}Ta5d6ff ops/sTa5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftest_concurrent_read_write_contentionTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Writers inserting while readers query — simulates real app usage."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Contention] Mixed read/write:Ta5d6ff"Tb4b4b4)
Te6edf3num_writers Tff7b72= T79c0ff4
Te6edf3num_readers Tff7b72= T79c0ff4
Te6edf3ops_per_thread Tff7b72= T79c0ff50
Te6edf3write_errors Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3read_errors Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3write_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3read_durations Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffwriterTb4b4b4(Te6edf3thread_idTb4b4b4)Tb4b4b4:
Te6edf3local_durs Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3peer Tff7b72= Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4)
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Te6edf3ops_per_threadTb4b4b4)Tb4b4b4:
Te6edf3msg Tff7b72= Te6edf3make_messageTb4b4b4(Te6edf3peerTb4b4b4, Te6edf3thread_id Tff7b72* T79c0ff10000 Tff7b72+ Te6edf3iTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffupsert_lxmf_messageTb4b4b4, Te6edf3msgTb4b4b4)
Te6edf3local_dursTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3write_errorsTff7b72.Td2a8ffappendTb4b4b4(Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3lockTb4b4b4:
Te6edf3write_durationsTff7b72.Td2a8ffextendTb4b4b4(Te6edf3local_dursTb4b4b4)

Tff7b72def Td2a8ffreaderTb4b4b4(Te6edf3_thread_idTb4b4b4)Tb4b4b4:
Te6edf3local_durs Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(Te6edf3ops_per_threadTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffget_conversationsTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Te6edf3limitTff7b72=T79c0ff20Tb4b4b4,
Tb4b4b4)
Te6edf3local_dursTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3read_errorsTff7b72.Td2a8ffappendTb4b4b4(Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3lockTb4b4b4:
Te6edf3read_durationsTff7b72.Td2a8ffextendTb4b4b4(Te6edf3local_dursTb4b4b4)

Te6edf3writers Tff7b72= Tb4b4b4[
Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3writerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3tTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3t Tff7b72in Tffa657rangeTb4b4b4(Te6edf3num_writersTb4b4b4)
Tb4b4b4]
Te6edf3readers Tff7b72= Tb4b4b4[
Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3readerTb4b4b4, Te6edf3argsTff7b72=Tb4b4b4(Te6edf3tTb4b4b4,Tb4b4b4)Tb4b4b4) Tff7b72for Te6edf3t Tff7b72in Tffa657rangeTb4b4b4(Te6edf3num_readersTb4b4b4)
Tb4b4b4]

Te6edf3t0 Tff7b72= Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3writers Tff7b72+ Te6edf3readersTb4b4b4:
Te6edf3tTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72for Te6edf3t Tff7b72in Te6edf3writers Tff7b72+ Te6edf3readersTb4b4b4:
Te6edf3tTff7b72.Td2a8ffjoinTb4b4b4(Tb4b4b4)
Te6edf3wall_ms Tff7b72= Tb4b4b4(Te6edf3timeTff7b72.Td2a8ffperf_counterTb4b4b4(Tb4b4b4) Tff7b72- Te6edf3t0Tb4b4b4) Tff7b72* T79c0ff1000

Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Wall time: Tffd700{Te6edf3wall_msTffd700:Ta5d6ff.0fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)
Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffcontention_writesTa5d6ff"Tb4b4b4, Te6edf3write_durationsTb4b4b4)
Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffcontention_readsTa5d6ff"Tb4b4b4, Te6edf3read_durationsTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tffa657lenTb4b4b4(Te6edf3write_errorsTb4b4b4)Tb4b4b4, T79c0ff0Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffWrite errors: Tffd700{Te6edf3write_errorsTb4b4b4[Tb4b4b4:T79c0ff5Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Tffa657lenTb4b4b4(Te6edf3read_errorsTb4b4b4)Tb4b4b4, T79c0ff0Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffRead errors: Tffd700{Te6edf3read_errorsTb4b4b4[Tb4b4b4:T79c0ff5Tb4b4b4]Tffd700}Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_like_search_scalingTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Exercise LIKE search at scale (catches missing indexes / bad plans)."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Scaling] LIKE search across data sizes:Ta5d6ff"Tb4b4b4)

T8b949e# Message search on the existing 10k dataset
Te6edf3_Tb4b4b4, Te6edf3ms_msg Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffhandlerTff7b72.Td2a8ffsearch_messagesTb4b4b4,
Ta5d6ff"Ta5d6fflocal_hashTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffContent bodyTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Message LIKE search (Tffd700{Tff7b72selfTff7b72.Td2a8ffNUM_MESSAGESTffd700}Ta5d6ff rows): Tffd700{Te6edf3ms_msgTffd700:Ta5d6ff.2fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3ms_msgTb4b4b4, T79c0ff500Tb4b4b4, Ta5d6ff"Ta5d6ffMessage LIKE search > 500ms on 10k rowsTa5d6ff"Tb4b4b4)

T8b949e# Announce search on the existing 5k dataset
Te6edf3_Tb4b4b4, Te6edf3ms_ann Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffannounce_mgrTff7b72.Td2a8ffget_filtered_announcesTb4b4b4,
Te6edf3aspectTff7b72=Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,
Te6edf3queryTff7b72=Ta5d6ff"Ta5d6ffabcTa5d6ff"Tb4b4b4,
Te6edf3limitTff7b72=T79c0ff50Tb4b4b4,
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Announce LIKE search (Tffd700{Tff7b72selfTff7b72.Td2a8ffNUM_ANNOUNCESTffd700}Ta5d6ff rows): Tffd700{Te6edf3ms_annTffd700:Ta5d6ff.2fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3ms_annTb4b4b4, T79c0ff200Tb4b4b4, Ta5d6ff"Ta5d6ffAnnounce LIKE search > 200ms on 5k rowsTa5d6ff"Tb4b4b4)

T8b949e# Contacts search
Te6edf3_Tb4b4b4, Te6edf3ms_con Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffcontactsTff7b72.Td2a8ffget_contactsTb4b4b4, Te6edf3searchTff7b72=Ta5d6ff"Ta5d6ffContactTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Contacts LIKE search (Tffd700{Tff7b72selfTff7b72.Td2a8ffNUM_CONTACTSTffd700}Ta5d6ff rows): Tffd700{Te6edf3ms_conTffd700:Ta5d6ff.2fTffd700}Ta5d6ffmsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3ms_conTb4b4b4, T79c0ff50Tb4b4b4, Ta5d6ff"Ta5d6ffContacts LIKE search > 50msTa5d6ff"Tb4b4b4)

T8b949e# ===================================================================
T8b949e# N+1 BATCH OPERATIONS — transaction wrapping regression tests
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_mark_conversations_as_read_batchTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""mark_conversations_as_read should be fast for large batches (transaction-wrapped)."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Batch] mark_conversations_as_read:Ta5d6ff"Tb4b4b4)
Te6edf3hashes Tff7b72= Tb4b4b4[Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffmark_conversations_as_readTb4b4b4, Te6edf3hashesTb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffmark_read_200Ta5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4, T79c0ff50Tb4b4b4, Ta5d6ff"Ta5d6ffmark_conversations_as_read(200) p95 > 50msTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_mark_all_notifications_as_viewed_batchTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""mark_all_notifications_as_viewed should be fast for large batches."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Batch] mark_all_notifications_as_viewed:Ta5d6ff"Tb4b4b4)
Te6edf3hashes Tff7b72= Tb4b4b4[Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffmark_all_notifications_as_viewedTb4b4b4,
Te6edf3hashesTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffmark_viewed_200Ta5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(
Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4,
T79c0ff50Tb4b4b4,
Ta5d6ff"Ta5d6ffmark_all_notifications_as_viewed(200) p95 > 50msTa5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8fftest_move_conversations_to_folder_batchTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""move_conversations_to_folder should be fast for large batches."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Batch] move_conversations_to_folder:Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffcreate_folderTb4b4b4(Ta5d6ff"Ta5d6ffperf_test_folderTa5d6ff"Tb4b4b4)
Te6edf3folders Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffget_all_foldersTb4b4b4(Tb4b4b4)
Te6edf3folder_id Tff7b72= Te6edf3foldersTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4]

Te6edf3hashes Tff7b72= Tb4b4b4[Te6edf3secretsTff7b72.Td2a8fftoken_hexTb4b4b4(T79c0ff16Tb4b4b4) Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff200Tb4b4b4)Tb4b4b4]
Te6edf3durations Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3_ Tff7b72in Tffa657rangeTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4:
Te6edf3_Tb4b4b4, Te6edf3ms Tff7b72= Te6edf3timed_callTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffmessagesTff7b72.Td2a8ffmove_conversations_to_folderTb4b4b4,
Te6edf3hashesTb4b4b4,
Te6edf3folder_idTb4b4b4,
Tb4b4b4)
Te6edf3durationsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3msTb4b4b4)

Te6edf3stats Tff7b72= Te6edf3latency_reportTb4b4b4(Ta5d6ff"Ta5d6ffmove_folder_200Ta5d6ff"Tb4b4b4, Te6edf3durationsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessTb4b4b4(
Te6edf3statsTb4b4b4[Ta5d6ff"Ta5d6ffp95Ta5d6ff"Tb4b4b4]Tb4b4b4,
T79c0ff50Tb4b4b4,
Ta5d6ff"Ta5d6ffmove_conversations_to_folder(200) p95 > 50msTa5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e# ===================================================================
T8b949e# INDEX VERIFICATION — confirm new indexes are used
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_indexes_existTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Verify critical indexes exist in the schema."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Indexes] Checking critical indexes exist:Ta5d6ff"Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(
Ta5d6ff"Ta5d6ffSELECT name FROM sqlite_master WHERE type=Ta5d6ff'Ta5d6ffindexTa5d6ff'Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3index_names Tff7b72= Tb4b4b4{Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4] Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4}

Te6edf3expected Tff7b72= Tb4b4b4[
Ta5d6ff"Ta5d6ffidx_contacts_lxmf_addressTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_contacts_lxst_addressTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_notifications_is_viewedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_map_drawings_identity_hashTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_map_drawings_identity_nameTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_voicemails_is_readTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_archived_pages_created_atTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_lxmf_messages_state_peerTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_lxmf_messages_peer_hashTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_lxmf_messages_peer_tsTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_announces_updated_atTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffidx_announces_aspectTa5d6ff"Tb4b4b4,
Tb4b4b4]
Tff7b72for Te6edf3idx Tff7b72in Te6edf3expectedTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Te6edf3idxTb4b4b4, Te6edf3index_namesTb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffMissing index: Tffd700{Te6edf3idxTffd700}Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3idxTffd700}Ta5d6ff: OKTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8fftest_pragmas_appliedTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Verify performance PRAGMAs are active."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[PRAGMAs] Checking applied PRAGMAs:Ta5d6ff"Tb4b4b4)
Te6edf3journal Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ff_get_pragma_valueTb4b4b4(Ta5d6ff"Ta5d6ffjournal_modeTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff journal_mode: Tffd700{Te6edf3journalTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3journalTb4b4b4, Ta5d6ff"Ta5d6ffwalTa5d6ff"Tb4b4b4)

Te6edf3sync Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ff_get_pragma_valueTb4b4b4(Ta5d6ff"Ta5d6ffsynchronousTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff synchronous: Tffd700{Te6edf3syncTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3syncTb4b4b4, T79c0ff1Tb4b4b4) T8b949e# NORMAL = 1

Te6edf3temp_store Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ff_get_pragma_valueTb4b4b4(Ta5d6ff"Ta5d6fftemp_storeTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff temp_store: Tffd700{Te6edf3temp_storeTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3temp_storeTb4b4b4, T79c0ff2Tb4b4b4) T8b949e# MEMORY = 2

Te6edf3cache_size Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ff_get_pragma_valueTb4b4b4(Ta5d6ff"Ta5d6ffcache_sizeTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff cache_size: Tffd700{Te6edf3cache_sizeTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertLessEqualTb4b4b4(Te6edf3cache_sizeTb4b4b4, Tff7b72-T79c0ff8000Tb4b4b4)

T8b949e# ===================================================================
T8b949e# QUERY PLAN CHECKS — confirm indexes are actually used
T8b949e# ===================================================================

Tff7b72def Td2a8fftest_query_plan_messages_by_peerTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""The most common message query should use peer_hash index."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Query Plan] Messages by peer_hash:Ta5d6ff"Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(
Ta5d6ff"Ta5d6ffEXPLAIN QUERY PLAN SELECT * FROM lxmf_messages WHERE peer_hash = ? ORDER BY id DESC LIMIT 50Ta5d6ff"Tb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3plan Tff7b72= Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Tffa657strTb4b4b4(Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffdetailTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3planTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffidx_lxmf_messages_peer_hashTa5d6ff"Tb4b4b4, Te6edf3planTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4)

Tff7b72def Td2a8fftest_query_plan_announces_by_aspectTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Announce filtering by aspect should use the aspect index."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Query Plan] Announces by aspect:Ta5d6ff"Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(
Ta5d6ff"Ta5d6ffEXPLAIN QUERY PLAN SELECT * FROM announces WHERE aspect = ? ORDER BY updated_at DESC LIMIT 50Ta5d6ff"Tb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3plan Tff7b72= Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Tffa657strTb4b4b4(Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffdetailTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3planTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffidx_announces_aspectTa5d6ff"Tb4b4b4, Te6edf3planTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4)

Tff7b72def Td2a8fftest_query_plan_failed_messages_state_peerTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""The failed_count subquery should use the state+peer composite index."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Query Plan] Failed messages (state, peer_hash):Ta5d6ff"Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(
Ta5d6ff"Ta5d6ffEXPLAIN QUERY PLAN SELECT COUNT(*) FROM lxmf_messages WHERE state = Ta5d6ff'Ta5d6fffailedTa5d6ff'Ta5d6ff AND peer_hash = ?Ta5d6ff"Tb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6fftestTa5d6ff"Tb4b4b4,Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3plan Tff7b72= Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Tffa657strTb4b4b4(Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffdetailTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3planTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffidx_lxmf_messages_state_peerTa5d6ff"Tb4b4b4, Te6edf3planTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4)

Tff7b72def Td2a8fftest_query_plan_notifications_unreadTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Notification unread filter should use the is_viewed index."""
Tffa657printTb4b4b4(Ta5d6ff"Tffea00\nTa5d6ff[Query Plan] Notifications unread:Ta5d6ff"Tb4b4b4)
Te6edf3rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(
Ta5d6ff"Ta5d6ffEXPLAIN QUERY PLAN SELECT * FROM notifications WHERE is_viewed = 0 ORDER BY timestamp DESC LIMIT 50Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3plan Tff7b72= Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Tffa657strTb4b4b4(Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffdetailTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72for Te6edf3r Tff7b72in Te6edf3rowsTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3planTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertInTb4b4b4(Ta5d6ff"Ta5d6ffidx_notifications_is_viewedTa5d6ff"Tb4b4b4, Te6edf3planTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4)


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Te6edf3unittestTff7b72.Td2a8ffmainTb4b4b4(Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────